#============================================
# #知识点
# 继承是一种创建新类的方式，在Python中，新建的类可以继承一个或多个父类，新建的类可称为子类或派生类，
# 父类又可称为基类或超类
# class ParentClass1: #定义父类
#     pass
# class ParentClass2: #定义父类
#     pass
# class SubClass1(ParentClass1): #单继承
#     pass
# class SubClass2(ParentClass1,ParentClass2): #多继承
#     pass
# print(SubClass2.__bases__)
# 通过类的内置属性__bases__可以查看类继承的所有父类
# 为何要用继承:用来解决类与类之间代码冗余问题

# 继承
# 优点:子类可以同时遗传多个父类的属性，最大限度地重用代码
# 缺点:
# 1、违背人的思维习惯:继承表达的是种什么 ”是"什么的关系 
# 2、代码可读性会变差
# 3、扩展性变差
# 如果真的涉及到一个子类不可避免地要重用多个父类的属性，应该使用Mixins
#============================================
#基础实列
# class xuegongchu:
#     def __init__(self,name,age,gender) -> None:
#         self.name = name
#         self.age = age
#         self.gender = gender

# class Student(xuegongchu):
#     def __init__(self,name,age,gender,classes) -> None:
#         xuegongchu.__init__(self,name,age,gender)
#         self.classes = classes

#     def show(self):
#         print(f"{self.name} {self.age} {self.gender} {self.classes}")


# class Teather(xuegongchu):
#     def __init__(self,name,age,gender,level) -> None:
#         xuegongchu.__init__(self,name,age,gender)
#         self.level = level    

#     def show(self):
#           print(f"{self.name} {self.age} {self.gender} {self.level}")

# stundet1 = Student("小黑",18,"男","3班")
# stundet1.show()
# teather1 = Teather("向前",35,"男","10级")
# teather1.show()
# super() 调用super()会得到一个特殊的对象，该对象专门用来引用父类的属性，且严格按照MRO规定的顺序向后查找
# 提示：在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()。
# 这两种方式的区别是：方式一是跟继承没有关系的，而方式二的super()是依赖于继承的，
# 并且即使没有直接继承关系，super()仍然会按照MRO继续往后查找
class xuegongchu:
    def __init__(self,name,age,gender) -> None:
        self.name = name
        self.age = age
        self.gender = gender

class Student(xuegongchu):
    def __init__(self,name,age,gender,classes) -> None:
        self.name = name
        self.age = age
        self.gender = gender
        # super().__init__(name,age,gender)   #调用的是绑定方法，自动传入self
        self.classes = classes

    def show(self):
        print(f"{self.name} {self.age} {self.gender} {self.classes}")


class Teather(xuegongchu):
    def __init__(self,name,age,gender,level) -> None:
        super().__init__(name,age,gender)
        self.level = level    

    def show(self):
          print(f"{self.name} {self.age} {self.gender} {self.level}")

stundet1 = Student("小黑",18,"男","3班")
stundet1.show()
teather1 = Teather("向前",35,"男","10级")
teather1.show()
#============================================
#注：打印结果，不要用惯性思维
# class FOO:
#     def f1(self):
#         print('Foo.f1') 
#     def f2(self):
#         print('Foo.f2')
#         self.f1()
#         #FOO.f1(self)要想调用父类得f1用这个
# class Bar(FOO):
#     def f1(self):
#         print('Bar.f1')

# ojb = Bar()
# ojb.f2()
#============================================
# 继承原理
# python到底是如何实现继承的呢？ 对于你定义的每一个类，Python都会计算出一个方法解析顺序(MRO)列表，
# 该MRO列表就是一个简单的所有基类的线性顺序列表，如下
# >>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容，经典类没有该内置该方法
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, 
# 多继承结构为非菱形结构
# class E:
#     def test(self):
#         print('from E')
# class F:
#     def test(self):
#         print('from F')
# class B(E):
#     def test(self):
#         print('from B')
# class C(F):
#     def test(self):
#         print('from C')
# class D:
#     def test(self):
#         print('from D')
# class A(B, C, D):
#     # def test(self):
#     #     print('from A')
#     pass
# print(A.mro())
# obj = A()
# obj.test() 
#============================================
# 如果继承关系为菱形结构，那么经典类与新式类会有不同MRO，分别对应属性的两种查找方式：深度优先和python3为广度优先
#深度优先一条道走完，广度优先，最后走。
# 总结:
# 多继承到底要不用? ? ?
# 要用，但是规避几点问题
# 1、继承结构尽量不要过于复杂
# 2、要在多继承的背景下满足继承的什么"是"什么的关系=》mixins
#============================================